package user

import (
	"context"
	"time"

	"gitee.com/liuxuezhan/ar-platform/assets-rpc/internal/dao/model/query"
	schemaUser "gitee.com/liuxuezhan/ar-platform/assets-rpc/internal/dao/schema/user"
	"gitee.com/liuxuezhan/ar-platform/assets-rpc/pkg/xerrors"
	"gorm.io/gorm"
)

type WalletModel struct {
	ctx context.Context
	db  *gorm.DB
}

func (m *WalletModel) getDB() *gorm.DB {
	return m.db
}

func NewWalletModel(ctx context.Context, db *gorm.DB) *WalletModel {
	return &WalletModel{
		ctx: ctx,
		db:  db,
	}
}

func (m *WalletModel) GetBalance(userId int64) (*schemaUser.UserWallet, error) {
	g := query.Use(m.db).UserWallet
	userWallet, err := g.Where(g.UserId.Eq(userId)).First()
	if err != nil && err.Error() != "record not found" {
		return nil, err
	}
	if userWallet == nil {
		userWallet = &schemaUser.UserWallet{
			UserId:  userId,
			Balance: 0,
			Version: 0,
		}
		err := g.Create(userWallet)
		if err != nil {
			return nil, err
		}
	}

	return userWallet, nil
}

func (m *WalletModel) AddBalance(userId int64, amount float64, wallet *schemaUser.UserWallet) (*schemaUser.UserWallet, error) {
	userWallet, err := m.GetBalance(userId)
	if err != nil {
		return nil, err
	}
	result := m.db.Model(&schemaUser.UserWallet{}).
		Where("user_id = ?", userWallet.UserId).
		Where("version = ?", userWallet.Version).
		Updates(map[string]interface{}{
			"balance":        gorm.Expr("balance + ?", amount),
			"version":        gorm.Expr("version + ?", 1),
			"valid_mark":     gorm.Expr("valid_mark + ?", wallet.ValidMark),
			"total_recharge": gorm.Expr("total_recharge + ?", wallet.TotalRecharge),
		})
	if err := result.Error; err != nil {
		return nil, err
	}
	if result.RowsAffected == 0 {
		return nil, xerrors.ErrWalletBalanceAddFailed
	}
	// 更新数据
	userWallet.Balance = userWallet.Balance + amount
	userWallet.Version = userWallet.Version + 1
	userWallet.UpdatedAt = time.Now().Unix()
	userWallet.ValidMark = userWallet.ValidMark + wallet.ValidMark
	userWallet.TotalRecharge = userWallet.TotalRecharge + wallet.TotalRecharge

	return userWallet, nil
}

func (m *WalletModel) DeductBalance(userId int64, amount float64, wallet *schemaUser.UserWallet) (*schemaUser.UserWallet, error) {
	userWallet, err := m.GetBalance(userId)
	if err != nil {
		return nil, err
	}

	if userWallet.Balance < amount {
		return nil, xerrors.ErrWalletBalanceNotEnough
	}

	result := m.db.Model(&schemaUser.UserWallet{}).
		Where("user_id = ?", userWallet.UserId).
		Where("version = ?", userWallet.Version).
		Where("balance >= ?", amount).
		Updates(map[string]interface{}{
			"balance":        gorm.Expr("balance - ?", amount),
			"version":        gorm.Expr("version + ?", 1),
			"valid_consume":  gorm.Expr("valid_consume + ?", wallet.ValidConsume),
			"total_withdraw": gorm.Expr("total_withdraw + ?", wallet.TotalWithdraw),
		})
	if err := result.Error; err != nil {
		return nil, err
	}
	if result.RowsAffected == 0 {
		return nil, xerrors.ErrWalletBalanceInsufficient
	}
	// 更新数据
	userWallet.Balance = userWallet.Balance - amount
	userWallet.Version = userWallet.Version + 1
	userWallet.UpdatedAt = time.Now().Unix()
	userWallet.ValidConsume = userWallet.ValidConsume + wallet.ValidConsume
	userWallet.TotalWithdraw = userWallet.TotalWithdraw + wallet.TotalWithdraw

	return userWallet, nil
}

func (m *WalletModel) AddValidConsume(userId int64, validConsume float64) (*schemaUser.UserWallet, error) {
	userWallet, err := m.GetBalance(userId)
	if err != nil {
		return nil, err
	}
	result := m.db.Model(&schemaUser.UserWallet{}).
		Where("user_id = ?", userWallet.UserId).
		Where("version = ?", userWallet.Version).
		Updates(map[string]interface{}{
			"valid_consume": gorm.Expr("valid_consume + ?", validConsume),
			"version":       gorm.Expr("version + ?", 1),
		})
	if err := result.Error; err != nil {
		return nil, err
	}
	if result.RowsAffected == 0 {
		return nil, xerrors.ErrWalletValidConsumeAddFailed
	}
	// 更新数据
	userWallet.ValidConsume = userWallet.ValidConsume + validConsume
	userWallet.UpdatedAt = time.Now().Unix()

	return userWallet, nil
}

func (m *WalletModel) AddValidMark(userId int64, validMark float64) (*schemaUser.UserWallet, error) {
	userWallet, err := m.GetBalance(userId)
	if err != nil {
		return nil, err
	}
	result := m.db.Model(&schemaUser.UserWallet{}).
		Where("user_id = ?", userWallet.UserId).
		Where("version = ?", userWallet.Version).
		Updates(map[string]interface{}{
			"valid_mark": gorm.Expr("valid_mark + ?", validMark),
			"version":    gorm.Expr("version + ?", 1),
		})
	if err := result.Error; err != nil {
		return nil, err
	}
	if result.RowsAffected == 0 {
		return nil, xerrors.ErrWalletValidMarkAddFailed
	}
	// 更新数据
	userWallet.ValidMark = userWallet.ValidMark + validMark
	userWallet.UpdatedAt = time.Now().Unix()

	return userWallet, nil
}

func (m *WalletModel) SetValidMark(userId int64, validMark float64) error {
	userWallet, err := m.GetBalance(userId)
	if err != nil {
		return err
	}
	return m.db.Model(&schemaUser.UserWallet{}).
		Where("user_id = ?", userWallet.UserId).
		Where("version = ?", userWallet.Version).
		Updates(map[string]interface{}{
			"valid_mark": validMark,
			"version":    gorm.Expr("version + ?", 1),
		}).Error
}

func (m *WalletModel) ClearMarkConsume(userId int64) error {
	return m.db.Model(&schemaUser.UserWallet{}).
		Where("user_id = ?", userId).
		Updates(map[string]interface{}{
			"valid_mark":    0,
			"valid_consume": 0,
		}).Error
}

func (m *WalletModel) FindUserWallet(userId int64) (*schemaUser.UserWallet, error) {
	var userWallet schemaUser.UserWallet
	err := m.db.Model(&schemaUser.UserWallet{}).
		Where("user_id = ?", userId).
		First(&userWallet).Error
	if err != nil {
		return nil, err
	}
	return &userWallet, nil
}

func (m *WalletModel) ListUserWallet(userIds []int64) ([]*schemaUser.UserWallet, error) {
	var userWallets []*schemaUser.UserWallet
	err := m.db.Where("user_id in ?", userIds).Order("user_id desc").Find(&userWallets).Error
	if err != nil {
		return nil, err
	}
	return userWallets, nil
}
